#ifndef __QUEUE_BLOCK_H_
#define __QUEUE_BLOCK_H_ 

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <queue>

#define nullptr NULL
class BlockQueue{
  private:
    std::queue<int> q;
    size_t cap;
    pthread_mutex_t l_lock;
    pthread_cond_t c_cond;
    pthread_cond_t p_cond;
  public:
    bool IsFull()
    {
      return q.size() >= cap;
    }
    bool IsEmpty()
    {
      return q.empty();
    }

    void LockQueue()
    {
      pthread_mutex_lock(&l_lock);
    }

    void unLockQueue()
    {
      pthread_mutex_lock(&l_lock);
    }
    
    void WakeUpProductor()
    {


      pthread_cond_signal(&p_cond);
    }

    void WakeUpComsumer()
    {


      pthread_cond_signal(&c_cond);
    }

    void ProducterWait()
    {
      pthread_cond_wait(&p_cond, &l_lock);
    }

    void ComsumerWait()
    {
      pthread_cond_wait(&c_cond, &l_lock);
    }
  public:
    BlockQueue(int _cap):cap(_cap)
    {
      pthread_mutex_init(&l_lock,nullptr);
      pthread_cond_init(&c_cond,nullptr);
      pthread_cond_init(&p_cond,nullptr);
    }
    void Put(int in)
    {
      LockQueue();
      if(IsFull()){ //bug!
        WakeUpComsumer();
        ProducterWait();
      }
      q.push(in);
      unLockQueue();
    }

    void Get(int &out)
    {
      LockQueue();
      if(IsEmpty())
      {
        WakeUpProductor();
        ComsumerWait();
      }
      out = q.front();
      q.pop();
      unLockQueue();
    }
    ~BlockQueue()
    {
      pthread_mutex_destroy(&l_lock);
      pthread_cond_destroy(&c_cond);
      pthread_cond_destroy(&p_cond);
    }
};


#endif 
